package com.secsbrain.development.web.ws.handle;

import com.alibaba.fastjson.JSON;
import com.secsbrain.development.web.ws.base.BaseHandler;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 处理实时日志,多实例
 * Created by yangyang.zhang on 2017-6-25.
 */
@Component
public class WebLogHandler extends BaseHandler {
    private static final Pattern LOG_END_PATTERN = Pattern.compile("=====>command:\\[.*]");
    @Value("${exec.log.path:/home/logs/execLog}")
    private String execLogPath;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
        session.getAttributes().put(IS_BREAK_KEY, false);
        session.getAttributes().put(IS_RUNNING_KEY, false);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        closeStream(session);
    }

    private static final String IS_BREAK_KEY = "IS_BREAK";
    private static final String IS_RUNNING_KEY = "IS_RUNNING";

    private void closeStream(WebSocketSession session) {
        session.getAttributes().put(IS_BREAK_KEY, true);
    }

    private static final long READ_LOG_TIMEOUT = 60 * 1000 * 5;
    private static final String BLANK = " ";

    private boolean needBreak(WebSocketSession session) {
        return Boolean.parseBoolean(String.valueOf(session.getAttributes().get(IS_BREAK_KEY)));
    }

    private void setBreak(WebSocketSession session, boolean flag) {
        session.getAttributes().put(IS_BREAK_KEY, flag);
    }

    private boolean isRunning(WebSocketSession session) {
        return Boolean.parseBoolean(String.valueOf(session.getAttributes().get(IS_RUNNING_KEY)));
    }

    private void setRunning(WebSocketSession session, boolean flag) {
        session.getAttributes().put(IS_RUNNING_KEY, flag);
    }

    private void printMsg(List<Long> taskIds, WebSocketSession session) throws IOException, InterruptedException {
        LOGGER.info("[WebLogHandler:printMsg] begin to send msg,sessionId:[{}]", session.getId());
        try {
            while (isRunning(session)) {
                setBreak(session, true);
                Thread.sleep(2000);
            }
            setRunning(session, true);
            setBreak(session, false);
            for (long taskId : taskIds) {
                Path path = Paths.get(execLogPath, String.valueOf(taskId));
                /*避免执行线程尚未创建日志文件或文件存在但新日志未写入，等待5秒*/
                session.sendMessage(new TextMessage("正在载入任务ID:[" + taskId + "]的日志文件,请稍等..."));
                Thread.sleep(2000);
                int waitCount = 0;
                while (!Files.exists(path)) {
                    Thread.sleep(2000);
                    if (++waitCount > 15) {
                        session.sendMessage(new TextMessage("载入任务ID:[" + taskId + "]的日志文件超时..."));
                        return;
                    }
                }
                try (BufferedReader reader = Files.newBufferedReader(path)) {
                    String line;
                    /*空行等待时间*/
                    long currentTimeMillis = 0;
                    while (true) {
                        if (needBreak(session)) {
                            LOGGER.warn("[WebLogHandler:printMsg] break and stop to send message,sessionId:[{}],path:[{}]",
                                    session.getId(), path);
                            setRunning(session, false);
                            return;
                        }
                        line = reader.readLine();
                        if (line == null) {
                            System.out.println("读取到文件结尾=>");
                            /*执行线程尚未写入日志文件，等待5秒*/
                            if (currentTimeMillis == 0) {
                                currentTimeMillis = System.currentTimeMillis();
                            } else if (System.currentTimeMillis() - currentTimeMillis > READ_LOG_TIMEOUT) {
                                session.sendMessage(new TextMessage("读取任务ID:[" + taskId + "]的日志文件超时..."));
                                break;
                            }
                            Thread.sleep(1000);
                        } else {
                            Thread.sleep(30);
                            /*TOMCAT 空行bug*/
                            session.sendMessage(new TextMessage("".equals(line) ? BLANK : line));
                            Matcher matcher = LOG_END_PATTERN.matcher(line);
                            if (matcher.matches()) {
                                LOGGER.warn("[WebLogHandler:printMsg] send message finished,sessionId:[{}],path:[{}]",
                                        session.getId(), path);
                                break;
                            }
                        }
                    }
                }
            }
        } finally {
            setRunning(session, false);
        }
    }

    @Override
    @Deprecated
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        try {
            List<Long> taskIds = JSON.parseArray(message.getPayload(), Long.class);
            new Thread(() -> {
                try {
                    printMsg(taskIds, session);
                } catch (Exception e) {
                    try {
                        if (session.isOpen()) {
                            session.sendMessage(new TextMessage("出错了,任务ID:" + taskIds + ",日志文件不存在或已被删除！"));
                        }
                    } catch (IOException ex) {
                        LOGGER.warn("[WebLogHandler:onMessage] exception,sessionId:[{}],IOException:[{}]", session.getId(), ex);
                    }
                }
            }).start();
        } catch (Exception e) {
            LOGGER.warn("[WebLogHandler:onMessage] exception,sessionId:[{}],exception:[{}]", session.getId(), e);
            try {
                if (session.isOpen()) {
                    session.sendMessage(new TextMessage("数据格式有误！message:" + message));
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public String[] getPaths() {
        return new String[]{"/weblog"};
    }

}
